package rpc.serialize;

import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import rpc.netty.tcp.entity.MessageHeader;

/*********
 *
 *
 *@author 197
 *@date 2020/6/29 17:53
 *
 **/

public class ProtostuffSerializeUtil {

  /**
   * 避免每次序列化都重新申请Buffer空间
   */

  /**
   * 缓存Schema
   */
  private static final Map<Class<?>, Schema<?>> schemaCache = new ConcurrentHashMap<Class<?>, Schema<?>>();

  static {
    schemaCache.put(MessageHeader.class, RuntimeSchema.getSchema(MessageHeader.class));
  }

  public static <T> byte[] serialize(T obj) {

    if (obj == null) {
      throw new NullPointerException();
    }
    Class<T> clazz = (Class<T>) obj.getClass();
    Schema<T> schema = getSchema(clazz);
    LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
    byte[] data;
    try {
      data = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
    } finally {
      buffer.clear();
    }

    return data;
  }

  private static <T> Schema<T> getSchema(Class<T> clazz) {
    Schema<T> schema = (Schema<T>) schemaCache.get(clazz);
    if (schema == null) {
      //这个schema通过RuntimeSchema进行懒创建并缓存
      //所以可以一直调用RuntimeSchema.getSchema(),这个方法是线程安全的
      schema = RuntimeSchema.getSchema(clazz);
      if (schema != null) {
        schemaCache.put(clazz, schema);
      }
    }

    return schema;
  }

  public static <T> T deserialize(byte[] data, Class<T> clazz) {
    Schema<T> schema = getSchema(clazz);
    T obj = schema.newMessage();
    ProtostuffIOUtil.mergeFrom(data, obj, schema);
    return obj;
  }


}